Node.js Microservices

மைக்ரோசர்விஸ் கட்டமைப்பு மற்றும் Node.js இல் அதை செயல்படுத்துவதைக் கற்றுக்கொள்ளுங்கள்

மைக்ரோசர்விஸ்கள் அறிமுகம்

மைக்ரோசர்விஸ்கள் என்பது ஒரு பயன்பாட்டை சிறிய, தளர்வாக இணைக்கப்பட்ட சேவைகளின் தொகுப்பாக கட்டமைக்கும் ஒரு கட்டமைப்பு பாணியாகும். ஒவ்வொரு சேவையும்:

மைக்ரோசர்விஸ்கள் கட்டமைப்பு பாரம்பரிய மோனோலிதிக் பயன்பாடுகளுடன் ஒப்பிடும்போது வேகமான வளர்ச்சி சுழற்சிகள், சிறந்த அளவிடுதல் மற்றும் மேம்படுத்தப்பட்ட நெகிழ்வுத்தன்மை ஆகியவற்றை செயல்படுத்துகிறது.

மோனோலித்கள் vs மைக்ரோசர்விஸ்கள்

அம்சம் மோனோலிதிக் கட்டமைப்பு மைக்ரோசர்விஸ்கள் கட்டமைப்பு
கட்டமைப்பு ஒற்றை, ஒருங்கிணைந்த கோட்பேஸ் பல சிறிய சேவைகள்
விநியோகம் முழு பயன்பாடும் ஒரே நேரத்தில் விநியோகிக்கப்படுகிறது சேவைகள் சுயாதீனமாக விநியோகிக்கப்படுகின்றன
அளவிடுதல் முழு பயன்பாடும் ஒன்றாக அளவிடப்பட வேண்டும் தனிப்பட்ட சேவைகளை சுயாதீனமாக அளவிட முடியும்
வளர்ச்சி ஒற்றை தொழில்நுட்ப ஸ்டாக் சேவைக்கு சேவை வெவ்வேறு தொழில்நுட்பங்கள்
அணி கட்டமைப்பு பெரும்பாலும் ஒற்றை அணி பல அணிகள், ஒவ்வொன்றும் குறிப்பிட்ட சேவைகளை வைத்திருக்கும்
சிக்கலான தன்மை எளிமையான கட்டமைப்பு, சிக்கலான கோட்பேஸ் சிக்கலான கட்டமைப்பு, எளிமையான தனிப்பட்ட கோட்பேஸ்கள்

முக்கிய கோட்பாடுகள்

ஒற்றை பொறுப்பு - ஒவ்வொரு மைக்ரோசர்விஸும் ஒரு விஷயத்தை நன்றாகச் செய்வதில் கவனம் செலுத்த வேண்டும் - ஒரு ஒற்றை வணிக திறனை செயல்படுத்துவது
மையமற்ற தன்மை - எல்லாவற்றையும் மையமற்றதாக்குங்கள்: ஆட்சி, தரவு மேலாண்மை, மற்றும் கட்டமைப்பு முடிவுகள்
தன்னாட்சி சேவைகள் - சேவைகள் மற்றவர்களை பாதிக்காமல் சுயாதீனமாக மாற்றவும் விநியோகிக்கவும் முடியும்
டொமைன்-டிரிவன் டிசைன் - தொழில்நுட்ப செயல்பாடுகளை விட வணிக டொமைன்களைச் சுற்றி சேவைகளை வடிவமைக்கவும்
நெகிழ்வுத்தன்மை - பிற சேவைகளின் தோல்வியை கையாள சேவைகள் வடிவமைக்கப்பட வேண்டும்
கண்காணிப்பு - சேவைகளுக்கிடையே விரிவான கண்காணிப்பு, பதிவு மற்றும் ட்ரேசிங்கை செயல்படுத்தவும்

💡 சிறந்த நடைமுறை:

ஒரு பயன்பாட்டை மைக்ரோசர்விஸ்களாக பிரிப்பதற்கு முன் ஒரு தெளிவான டொமைன் மாடல் மற்றும் கட்டுப்படுத்தப்பட்ட சூழல்களை அடையாளம் காண தொடங்கவும்.

மைக்ரோசர்விஸ்களுக்கான Node.js

Node.js பல காரணங்களுக்காக மைக்ரோசர்விஸ்கள் கட்டமைப்புக்கு குறிப்பாக பொருத்தமானது:

இலகுவான மற்றும் வேகமான

Node.js ஒரு சிறிய காலடி பதிவைக் கொண்டுள்ளது மற்றும் விரைவாகத் தொடங்குகிறது, இது விரைவாக அளவிட வேண்டிய மைக்ரோசர்விஸ்களுக்கு ஏற்றது

அசின்க்ரோனஸ் மற்றும் நிகழ்வு-இயக்கப்பட்ட

Node.js இன் நான்-பிளாக்கிங் I/O மாடல் சேவைகளுக்கிடையே பல ஒரே நேர இணைப்புகளை கையாளுவதற்கு திறமையானதாக்குகிறது

JSON ஆதரவு

முதல்-தர JSON ஆதரவு மைக்ரோசர்விஸ்களுக்கிடையே தரவு பரிமாற்றத்தை நேரடியாக்குகிறது

NPM எகோசிஸ்டம்

பரந்த பேக்கேஜ் எகோசிஸ்டம் சேவை கண்டறிதல், API கேட்வேக்கள், கண்காணிப்பு மற்றும் பலவற்றிற்கான நூலகங்களை வழங்குகிறது

எடுத்துக்காட்டு: எளிய Node.js மைக்ரோசர்விஸ்

// user-service.js
const express = require('express');
const app = express();

app.use(express.json());

// In-memory user database for demonstration
const users = [
  { id: 1, name: 'John Doe', email: 'john@example.com' },
  { id: 2, name: 'Jane Smith', email: 'jane@example.com' }
];

// Get all users
app.get('/users', (req, res) => {
  res.json(users);
});

// Get user by ID
app.get('/users/:id', (req, res) => {
  const user = users.find(u => u.id === parseInt(req.params.id));
  if (!user) return res.status(404).json({ message: 'User not found' });
  res.json(user);
});

// Create a new user
app.post('/users', (req, res) => {
  const newUser = {
    id: users.length + 1,
    name: req.body.name,
    email: req.body.email
  };
  users.push(newUser);
  res.status(201).json(newUser);
});

const PORT = process.env.PORT || 8080;
app.listen(PORT, () => {
  console.log(`User service running on port ${PORT}`);
});

சேவை தகவல்தொடர்பு

மைக்ரோசர்விஸ்கள் ஒருவருக்கொருவர் தகவல்தொடர்பு கொள்ள வழிகளை வேண்டும்.

இரண்டு அடிப்படை அணுகுமுறைகள் உள்ளன:

சின்க்ரோனஸ் தகவல்தொடர்பு

சேவைகள் ஒருவருக்கொருவர் APIகளை நேரடியாக அழைக்கின்றன, ஒரு ரியல்-டைம் கோரிக்கை-பதில் ஓட்டத்தை உருவாக்குகின்றன:

REST

எளிமையான, பரவலாகப் பயன்படுத்தப்படும், நிலையற்ற தகவல்தொடர்பு

GraphQL

ஒரு ஒற்றை எண்ட்பாயிண்டுடன் நெகிழ்வான வினவல்கள்

gRPC

ப்ரோட்டோகால் பஃபர்களைப் பயன்படுத்தும் உயர்-பெர்ஃபார்மன்ஸ் RPC பிரேம்வர்க்

எடுத்துக்காட்டு: சேவைகளுக்கிடையே REST தகவல்தொடர்பு

// order-service.js calling the user-service
const axios = require('axios');

async function getUserDetails(userId) {
  try {
    const response = await axios.get(`http://user-service:3001/users/${userId}`);
    return response.data;
  } catch (error) {
    console.error(`Error fetching user ${userId}:`, error.message);
    throw new Error('User service unavailable');
  }
}

// Route handler in order service
app.post('/orders', async (req, res) => {
  const { userId, products } = req.body;
  
  try {
    // Get user data from user service
    const user = await getUserDetails(userId);
    
    // Check product availability from product service
    const productStatus = await checkProductAvailability(products);
    
    if (!productStatus.allAvailable) {
      return res.status(400).json({ error: 'Some products are unavailable' });
    }
    
    // Create the order
    const order = await createOrder(userId, products, user.shippingAddress);
    
    res.status(201).json(order);
  } catch (error) {
    console.error('Order creation failed:', error);
    res.status(500).json({ error: 'Failed to create order' });
  }
});

⚠️ குறிப்பு:

சின்க்ரோனஸ் தகவல்தொடர்பு சேவைகளுக்கிடையே நேரடி சார்புகளை உருவாக்குகிறது. அழைக்கப்படும் சேவை கீழே இருந்தால் அல்லது மெதுவாக இருந்தால், அது அழைக்கும் சேவையை பாதிக்கிறது, இது தொடர் தோல்விகளை ஏற்படுத்தக்கூடும்.

அசின்க்ரோனஸ் தகவல்தொடர்பு

சேவைகள் உடனடி பதில்களுக்காக காத்திராமல் மெசேஜ் ப்ரோக்கர்கள் அல்லது நிகழ்வு பஸ்கள் மூலம் தகவல்தொடர்பு கொள்கின்றன:

மெசேஜ் வரிசைகள்

பாயிண்ட்-டு-பாயிண்ட் மெசேஜிங்கிற்கான RabbitMQ, ActiveMQ

பப்/சப்

பல சப்ஸ்கிரைபர்களுக்கு மெசேஜ்களை வெளியிடுவதற்கான Kafka, Redis Pub/Sub

நிகழ்வு ஸ்ட்ரீமிங்

தரவு ஸ்ட்ரீம்களை கையாளுவதற்கான Kafka, AWS Kinesis

எடுத்துக்காட்டு: நிகழ்வு பஸ் கொண்ட நிகழ்வு-இயக்கப்பட்ட தகவல்தொடர்பு

// order-service.js publishing an event
const axios = require('axios');

async function publishEvent(eventType, data) {
  try {
    await axios.post('http://event-bus:3100/events', {
      type: eventType,
      data: data,
      source: 'order-service',
      timestamp: new Date().toISOString()
    });
    console.log(`Published event: ${eventType}`);
  } catch (error) {
    console.error(`Failed to publish event ${eventType}:`, error.message);
    // Store failed events for retry
    storeFailedEvent(eventType, data, error);
  }
}

// Create an order and publish event
app.post('/orders', async (req, res) => {
  try {
    const order = await createOrder(req.body);
    
    // Publish event for other services
    await publishEvent('order.created', order);
    
    res.status(201).json(order);
  } catch (error) {
    res.status(500).json({ error: 'Order creation failed' });
  }
});

சேவை தோல்விகளை கையாளுதல்

மைக்ரோசர்விஸ்களில், தகவல்தொடர்பு தோல்விகளை கையாளுவதற்கான உத்திகள் உங்களுக்குத் தேவை:

பேட்டர்ன் விளக்கம் எப்போது பயன்படுத்துவது
சர்க்யூட் பிரேக்கர் தோல்வியுற்ற சேவைகளுக்கான கோரிக்கைகளை தற்காலிகமாக நிறுத்துகிறது, தொடர் தோல்விகளை தடுக்கிறது சேவைகள் தோல்வியுற்ற சார்புகளிலிருந்து பாதுகாப்பு தேவைப்படும் போது
பேக்அஃப் உடன் மீண்டும் முயற்சிக்கவும் அதிகரிக்கும் தாமதங்களுடன் தோல்வியுற்ற கோரிக்கைகளை தானாகவே மீண்டும் முயற்சிக்கிறது விரைவில் தீர்க்கக்கூடிய தற்காலிக தோல்விகளுக்கு
டைம்அவுட் பேட்டர்ன் பதில்களுக்காக காத்திருக்க அதிகபட்ச நேரத்தை அமைக்கிறது மெதுவான சேவைகளில் நூல்களைத் தடுக்காமல் இருக்க
பல்க்ஹெட் பேட்டர்ன் அவை அனைத்து வளங்களையும் உட்கொள்வதைத் தடுக்க தோல்விகளை தனிமைப்படுத்துகிறது கூறுகளுக்குள் தோல்விகளைக் கொண்டிருக்க
ஃபால்பேக் பேட்டர்ன் ஒரு சேவை தோல்வியுற்றால் மாற்று பதிலை வழங்குகிறது தோல்விகளின் போது அடிப்படை செயல்பாட்டை பராமரிக்க

எடுத்துக்காட்டு: சர்க்யூட் பிரேக்கர் செயல்படுத்தல்

const CircuitBreaker = require('opossum');

// Configure the circuit breaker
const options = {
  failureThreshold: 50,        // Open after 50% of requests fail
  resetTimeout: 10000,         // Try again after 10 seconds
  timeout: 8080,               // Time before request is considered failed
  errorThresholdPercentage: 50 // Error percentage to open circuit
};

// Create a circuit breaker for the user service
const getUserDetailsBreaker = new CircuitBreaker(getUserDetails, options);

// Add listeners for circuit state changes
getUserDetailsBreaker.on('open', () => {
  console.log('Circuit OPEN - User service appears to be down');
});

getUserDetailsBreaker.on('halfOpen', () => {
  console.log('Circuit HALF-OPEN - Testing user service');
});

getUserDetailsBreaker.on('close', () => {
  console.log('Circuit CLOSED - User service restored');
});

// Use the circuit breaker in the route handler
app.get('/orders/:orderId', async (req, res) => {
  const orderId = req.params.orderId;
  const order = await getOrderById(orderId);
  
  try {
    // Call the user service through the circuit breaker
    const user = await getUserDetailsBreaker.fire(order.userId);
    res.json({ order, user });
  } catch (error) {
    // If the circuit is open or the call fails, return fallback data
    console.error('Could not fetch user details:', error.message);
    res.json({
      order,
      user: { id: order.userId, name: 'User details unavailable' }
    });
  }
});

API கேட்வே பேட்டர்ன்

ஒரு API கேட்வே மைக்ரோசர்விஸ்கள் கட்டமைப்புக்கான அனைத்து கிளையன்ட் கோரிக்கைகளுக்கும் ஒரு ஒற்றை நுழைவு புள்ளியாக செயல்படுகிறது.

ஒரு API கேட்வேயின் பொறுப்புகள்

கோரிக்கை ரூட்டிங்: கிளையன்ட் கோரிக்கைகளை பொருத்தமான சேவைகளுக்கு இயக்குகிறது
API கம்போசிஷன்: பல சேவைகளிலிருந்து பதில்களை தொகுக்கிறது
ப்ரோட்டோகால் மொழிபெயர்ப்பு: ப்ரோட்டோகால்களுக்கு இடையே மாற்றுகிறது (எ.கா., HTTP to gRPC)
அங்கீகாரம் & அங்கீகாரம்: பாதுகாப்பு கவலைகளை கையாள்கிறது
ரேட் லிமிடிங்: APIயின் துஷ்பிரயோகத்தை தடுக்கிறது
கண்காணிப்பு & பதிவு: API பயன்பாட்டில் கண்ணுக்கு தெரியும் தன்மையை வழங்குகிறது

எடுத்துக்காட்டு: API கேட்வே செயல்படுத்தல்

const express = require('express');
const { createProxyMiddleware } = require('http-proxy-middleware');
const rateLimit = require('express-rate-limit');
const helmet = require('helmet');

const app = express();
const PORT = 8080;

// Add security headers
app.use(helmet());

// Apply rate limiting
const apiLimiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15 minutes
  max: 100,                // limit each IP to 100 requests per windowMs
  message: 'Too many requests from this IP, please try again later'
});
app.use('/api/', apiLimiter);

// Authentication middleware
function authenticate(req, res, next) {
  const token = req.headers.authorization;
  if (!token) {
    return res.status(401).json({ error: 'Unauthorized' });
  }
  // Verify token logic would go here
  next();
}

// Service registry (hardcoded for simplicity)
const serviceRegistry = {
  userService: 'http://localhost:3001',
  productService: 'http://localhost:3002',
  orderService: 'http://localhost:3003'
};

// Define proxy middleware for each service
const userServiceProxy = createProxyMiddleware({
  target: serviceRegistry.userService,
  changeOrigin: true,
  pathRewrite: { '^/api/users': '/users' }
});

const productServiceProxy = createProxyMiddleware({
  target: serviceRegistry.productService,
  changeOrigin: true,
  pathRewrite: { '^/api/products': '/products' }
});

const orderServiceProxy = createProxyMiddleware({
  target: serviceRegistry.orderService,
  changeOrigin: true,
  pathRewrite: { '^/api/orders': '/orders' }
});

// Route requests to appropriate services
app.use('/api/users', authenticate, userServiceProxy);
app.use('/api/products', productServiceProxy);
app.use('/api/orders', authenticate, orderServiceProxy);

app.listen(PORT, () => console.log(`API Gateway running on port ${PORT}`));

🚀 சிறந்த நடைமுறை:

உங்கள் சொந்தத்தை உருவாக்குவதற்குப் பதிலாக உற்பத்தி சூழல்களில் Kong, Netflix Zuul, அல்லது AWS API கேட்வே போன்ற கிளவுட் தீர்வுகள் போன்ற ஒரு அர்ப்பணிக்கப்பட்ட API கேட்வேயைப் பயன்படுத்தவும்.

சேவை கண்டறிதல்

சேவை கண்டறிதல் மைக்ரோசர்விஸ்கள் கடினமாக குறியிடப்பட்ட எண்ட்பாயிண்ட்கள் இல்லாமல் ஒருவருக்கொருவர் மாறும் முறையில் கண்டறிந்து தகவல்தொடர்பு கொள்ள அனுமதிக்கிறது.

சேவை கண்டறிதல் முறைகள்

முறை விளக்கம்
கிளையன்ட்-சைட் கண்டறிதல் கிளையன்ட்கள் சேவை இருப்பிடங்களைக் கண்டறிய ஒரு சேவை பதிவேட்டை வினவுகின்றன மற்றும் கோரிக்கைகளை தாங்களே லோட் பாலன்ஸ் செய்கின்றன
சர்வர்-சைட் கண்டறிதல் கிளையன்ட்கள் ஒரு ரூட்டர்/லோட் பாலன்சரை அழைக்கின்றன, இது சேவை நிகழ்வுகளை கண்டறிவதை கையாள்கிறது
DNS-அடிப்படையிலான கண்டறிதல் சேவைகள் DNS SRV பதிவுகள் அல்லது ஒத்த தொழில்நுட்பங்கள் மூலம் கண்டறியப்படுகின்றன

எடுத்துக்காட்டு: கிளையன்ட்-சைட் சேவை கண்டறிதல்

const axios = require('axios');

// Simple service registry client
class ServiceRegistry {
  constructor(registryUrl) {
    this.registryUrl = registryUrl;
    this.servicesCache = {};
    this.cacheTimeout = 60000; // 1 minute
  }

  async getService(name) {
    // Check cache first
    const cachedService = this.servicesCache[name];
    if (cachedService && cachedService.expiresAt > Date.now()) {
      return this._selectInstance(cachedService.instances);
    }

    // Fetch from registry if not in cache or expired
    try {
      const response = await axios.get(`${this.registryUrl}/services/${name}`);
      const instances = response.data.instances;

      if (!instances || instances.length === 0) {
        throw new Error(`No instances found for service: ${name}`);
      }

      // Update cache
      this.servicesCache[name] = {
        instances,
        expiresAt: Date.now() + this.cacheTimeout
      };

      return this._selectInstance(instances);
    } catch (error) {
      console.error(`Error fetching service ${name}:`, error.message);
      throw new Error(`Service discovery failed for ${name}`);
    }
  }

  // Simple round-robin load balancing
  _selectInstance(instances) {
    if (!instances._lastIndex) {
      instances._lastIndex = 0;
    } else {
      instances._lastIndex = (instances._lastIndex + 1) % instances.length;
    }

    return instances[instances._lastIndex];
  }
}

// Usage example
const serviceRegistry = new ServiceRegistry('http://registry:8500/v1');

async function callUserService(userId) {
  try {
    const serviceInstance = await serviceRegistry.getService('user-service');
    const response = await axios.get(`${serviceInstance.url}/users/${userId}`);
    return response.data;
  } catch (error) {
    console.error('Error calling user service:', error.message);
    throw error;
  }
}

பிரபலமான சேவை கண்டறிதல் கருவிகள்

Consul

சேவை கண்டறிதல் மற்றும் கான்ஃபிகரேஷன்

etcd

விநியோகிக்கப்பட்ட விசை-மதிப்பு கடை

ZooKeeper

கான்ஃபிகரேஷன் மற்றும் ஒத்திசைவுக்கான மையப்படுத்தப்பட்ட சேவை

Eureka

AWS கிளவுடுக்கான REST-அடிப்படையிலான சேவை கண்டறிதல்

Kubernetes

Kubernetes க்கான உள்ளமைக்கப்பட்ட சேவை கண்டறிதல்

தரவு மேலாண்மை உத்திகள்

மைக்ரோசர்விஸ்கள் கட்டமைப்பில் தரவை நிர்வகிப்பது மோனோலிதிக் பயன்பாடுகளை விட வெவ்வேறு அணுகுமுறைகளை தேவைப்படுத்துகிறது.

சேவைக்கு தரவுத்தளம்

ஒவ்வொரு மைக்ரோசர்விஸ்க்கும் அதன் சொந்த அர்ப்பணிக்கப்பட்ட தரவுத்தளம் உள்ளது, இது தளர்வான இணைப்பு மற்றும் சுயாதீன அளவிடுதலை உறுதி செய்கிறது.

💾 குறிப்பு:

சேவைக்கு தரவுத்தளம் பேட்டர்ன் ஒவ்வொரு சேவையும் அதன் தேவைகளுக்கு மிகவும் பொருத்தமான தரவுத்தள தொழில்நுட்பத்தை தேர்வு செய்ய அனுமதிக்கிறது (SQL, NoSQL, Graph DB, முதலியன).

விநியோகிக்கப்பட்ட பரிவர்த்தனைகள்

ACID பரிவர்த்தனைகள் இல்லாமல் சேவைகளில் தரவு நிலைத்தன்மையை பராமரிக்க சிறப்பு வடிவங்கள் தேவை:

சாகா பேட்டர்ன்

ஒரு ஒற்றை சேவைக்குள் தரவை புதுப்பிக்கும் உள்ளூர் பரிவர்த்தனைகளின் வரிசை. ஒவ்வொரு உள்ளூர் பரிவர்த்தனையும் அடுத்த பரிவர்த்தனையைத் தூண்டும் ஒரு நிகழ்வை வெளியிடுகிறது.

எடுத்துக்காட்டு: சாகா பேட்டர்ன் செயல்படுத்தல்

// In order-service.js

async function createOrder(orderData) {
  try {
    // Start the saga - create order
    const order = await orderRepository.create(orderData);

    // Publish event to trigger the next step in the saga
    await eventBus.publish('order.created', { orderId: order.id, ...orderData });

    return order;
  } catch (error) {
    console.error('Failed to create order:', error);
    throw error;
  }
}

// In payment-service.js
async function processPayment(event) {
  const { orderId, userId, amount } = event.data;

  try {
    // Process payment
    const payment = await paymentProcessor.charge(userId, amount, `Order ${orderId}`);

    // Publish success event
    await eventBus.publish('payment.succeeded', {
      orderId,
      paymentId: payment.id
    });
  } catch (error) {
    // Publish failure event to trigger compensation
    await eventBus.publish('payment.failed', {
      orderId,
      reason: error.message
    });
  }
}

// Compensating transaction in order-service.js
async function handlePaymentFailure(event) {
  const { orderId, reason } = event.data;

  // Update order status to 'payment-failed'
  await orderRepository.updateStatus(orderId, 'payment-failed', reason);

  // Notify customer about payment failure
  const order = await orderRepository.findById(orderId);
  await notificationService.notifyCustomer(order.userId, `Payment failed for order ${orderId}: ${reason}`);
}

நிகழ்வு சோர்சிங் மற்றும் CQRS

நிகழ்வு சோர்சிங் பயன்பாட்டு நிலையில் உள்ள அனைத்து மாற்றங்களையும் நிகழ்வுகளின் வரிசையாக சேமிக்கிறது. கமாண்ட் குவேரி ரெஸ்பான்சிபிலிட்டி செக்ரிகேஷன் (CQRS) வாசிப்பு மற்றும் எழுதும் செயல்பாடுகளை பிரிக்கிறது.

எடுத்துக்காட்டு: நிகழ்வு சோர்சிங்

// Event store
class EventStore {
  constructor() {
    this.events = [];
  }

  append(aggregateId, eventType, eventData) {
    const event = {
      id: this.events.length + 1,
      timestamp: new Date().toISOString(),
      aggregateId,
      type: eventType,
      data: eventData
    };

    this.events.push(event);
    this.publishEvent(event);
    return event;
  }

  getEventsForAggregate(aggregateId) {
    return this.events.filter(event => event.aggregateId === aggregateId);
  }

  publishEvent(event) {
    // Publish to subscribers/event bus
    console.log(`Event published: ${event.type}`);
  }
}

// Order aggregate
class Order {
  constructor(eventStore) {
    this.eventStore = eventStore;
  }

  createOrder(orderId, userId, items) {
    this.eventStore.append(orderId, 'OrderCreated', {
      userId,
      items,
      status: 'created'
    });
  }

  addItem(orderId, item) {
    this.eventStore.append(orderId, 'ItemAdded', { item });
  }

  removeItem(orderId, itemId) {
    this.eventStore.append(orderId, 'ItemRemoved', { itemId });
  }

  submitOrder(orderId) {
    this.eventStore.append(orderId, 'OrderSubmitted', {
      status: 'submitted',
      submittedAt: new Date().toISOString()
    });
  }

  // Rebuild the current state from events
  getOrder(orderId) {
    const events = this.eventStore.getEventsForAggregate(orderId);
    if (events.length === 0) return null;

    let order = { id: orderId, items: [] };

    for (const event of events) {
      switch (event.type) {
        case 'OrderCreated':
          order = { ...order, ...event.data };
          break;
        case 'ItemAdded':
          order.items.push(event.data.item);
          break;
        case 'ItemRemoved':
          order.items = order.items.filter(item => item.id !== event.data.itemId);
          break;
        case 'OrderSubmitted':
          order.status = event.data.status;
          order.submittedAt = event.data.submittedAt;
          break;
      }
    }

    return order;
  }
}

மைக்ரோசர்விஸ் வடிவங்கள்

மைக்ரோசர்விஸ்கள் கட்டமைப்புகளில் பொதுவான சவால்களை தீர்க்க பல வடிவமைப்பு வடிவங்கள் உதவுகின்றன:

API கேட்வே

அனைத்து கிளையன்ட் கோரிக்கைகளுக்கும் ஒரு ஒற்றை நுழைவு புள்ளி

சர்க்யூட் பிரேக்கர்

ஒரு சேவை பதிலளிக்காதபோது தொடர் தோல்விகளை தடுக்கிறது

சேவை கண்டறிதல்

கடினமாக குறியிடப்பட்ட இருப்பிடங்கள் இல்லாமல் சேவைகள் ஒருவருக்கொருவர் கண்டறிந்து தகவல்தொடர்பு கொள்ள அனுமதிக்கிறது

சாகா பேட்டர்ன்

பல சேவைகளில் விநியோகிக்கப்பட்ட பரிவர்த்தனைகளை நிர்வகிக்கிறது

CQRS

சிறந்த செயல்திறன் மற்றும் அளவிடுதலுக்காக வாசிப்பு மற்றும் எழுதும் செயல்பாடுகளை பிரிக்கிறது

பல்க்ஹெட் பேட்டர்ன்

அவை முழு கணினியிலும் பரவுவதை தடுக்க தோல்விகளை தனிமைப்படுத்துகிறது

எடுத்துக்காட்டு: API கேட்வே

// Basic API Gateway with Express
const express = require('express');
const { createProxyMiddleware } = require('http-proxy-middleware');

const app = express();

// Authentication middleware
app.use('/api', (req, res, next) => {
  const authHeader = req.headers.authorization;
  if (!authHeader) {
    return res.status(401).json({ message: 'Authentication required' });
  }
  // Validate token (simplified)
  next();
});

// Route to services
app.use('/api/users', createProxyMiddleware({
  target: 'http://user-service:8080',
  pathRewrite: { '^/api/users': '/users' }
}));

app.use('/api/orders', createProxyMiddleware({
  target: 'http://order-service:3001',
  pathRewrite: { '^/api/orders': '/orders' }
}));

app.listen(8000, () => {
  console.log('API Gateway running on port 8000');
});

எடுத்துக்காட்டு: சர்க்யூட் பிரேக்கர்

// circuit-breaker.js
class CircuitBreaker {
  constructor(request, options = {}) {
    this.request = request;
    this.state = 'CLOSED';
    this.failureCount = 0;
    this.successCount = 0;
    this.nextAttempt = Date.now();

    // Configurable thresholds
    this.failureThreshold = options.failureThreshold || 5;
    this.successThreshold = options.successThreshold || 2;
    this.timeout = options.timeout || 10000; // 10 seconds
  }

  async fire() {
    if (this.state === 'OPEN') {
      if (this.nextAttempt <= Date.now()) {
        this.state = 'HALF';
      } else {
        throw new Error('Circuit is OPEN');
      }
    }

    try {
      const response = await this.request();
      return this.success(response);
    } catch (err) {
      return this.fail(err);
    }
  }

  success(response) {
    if (this.state === 'HALF') {
      this.successCount++;
      if (this.successCount > this.successThreshold) {
        this.close();
      }
    }
    this.failureCount = 0;
    return response;
  }

  fail(err) {
    this.failureCount++;
    if (this.failureCount >= this.failureThreshold) {
      this.open();
    }
    return err;
  }

  open() {
    this.state = 'OPEN';
    this.nextAttempt = Date.now() + this.timeout;
  }

  close() {
    this.state = 'CLOSED';
    this.failureCount = 0;
    this.successCount = 0;
    this.nextAttempt = 0;
  }
}

module.exports = CircuitBreaker;

எடுத்துக்காட்டு: சாகா பேட்டர்ன்

// order-saga.js
class OrderSaga {
  constructor(orderId) {
    this.orderId = orderId;
    this.steps = [];
    this.compensations = [];
  }

  addStep(execute, compensate) {
    this.steps.push(execute);
    this.compensations.unshift(compensate);
    return this;
  }

  async execute() {
    const executedSteps = [];

    try {
      for (const [index, step] of this.steps.entries()) {
        await step();
        executedSteps.push(index);
      }
      return { success: true };
    } catch (error) {
      console.error('Saga execution failed, compensating...', error);
      await this.compensate(executedSteps);
      return { success: false, error };
    }
  }

  async compensate(executedSteps) {
    for (const stepIndex of executedSteps) {
      try {
        await this.compensations[stepIndex]();
      } catch (compError) {
        console.error('Compensation failed:', compError);
      }
    }
  }
}

// Example usage
const orderSaga = new OrderSaga('order-123')
  .addStep(
    () => orderService.createOrder({ id: 'order-123', items: ['item1', 'item2'] }),
    () => orderService.cancelOrder('order-123')
  )
  .addStep(
    () => paymentService.processPayment('order-123', 100.00),
    () => paymentService.refundPayment('order-123')
  );

orderSaga.execute();

🚀 மேம்பட்ட உதவிக்குறிப்பு:

சேவை-க்கு-சேவை தகவல்தொடர்பு, ட்ராஃபிக் மேலாண்மை, பாதுகாப்பு மற்றும் கண்காணிப்பு ஆகியவற்றைக் கையாள Istio அல்லது Linkerd போன்ற ஒரு சேவை மெஷைப் பயன்படுத்த கருதுங்கள்.

விநியோக உத்திகள்

மைக்ரோசர்விஸ்கள் நவீன விநியோக அணுகுமுறைகளிலிருந்து பயனடைகின்றன:

கண்டெய்னரைசேஷன்

Docker கண்டெய்னர்கள் ஒவ்வொரு மைக்ரோசர்விஸுக்கும் சீரான சூழல்களை வழங்குகின்றன

ஆர்கெஸ்ட்ரேஷன்

Kubernetes போன்ற கருவிகள் கண்டெய்னரைஸ்ட் சேவைகளின் விநியோகம், அளவிடுதல் மற்றும் மேலாண்மையை தானியக்கமாக்குகின்றன

தொடர் விநியோகம்

CI/CD பைப்லைன்கள் தனிப்பட்ட சேவைகளின் சோதனை மற்றும் விநியோகத்தை தானியக்கமாக்குகின்றன

இன்ஃப்ராஸ்ட்ரக்சர் ஆஸ் கோட்

Terraform அல்லது AWS CloudFormation போன்ற கருவிகள் ஒரு டிக்ளரேட்டிவ் வழியில் இன்ஃப்ராஸ்ட்ரக்சரை வரையறுக்கின்றன

எடுத்துக்காட்டு: Node.js மைக்ரோசர்விஸ்க்கான Dockerfile

FROM node:16-alpine

WORKDIR /app

COPY package*.json ./
RUN npm ci --only=production

COPY . .

EXPOSE 8080

CMD ["node", "user-service.js"]

எடுத்துக்காட்டு: Kubernetes விநியோகம்

apiVersion: apps/v1
kind: Deployment
metadata:
  name: user-service
spec:
  replicas: 3
  selector:
    matchLabels:
      app: user-service
  template:
    metadata:
      labels:
        app: user-service
    spec:
      containers:
      - name: user-service
        image: my-registry/user-service:latest
        ports:
        - containerPort: 8080
        env:
        - name: DB_HOST
          value: mongodb-service
        resources:
          limits:
            cpu: "0.5"
            memory: "512Mi"
          requests:
            cpu: "0.2"
            memory: "256Mi"

🔧 சிறந்த நடைமுறை:

மைக்ரோசர்விஸ்களை புதுப்பிக்கும் போது கீழே நேரத்தை மற்றும் ஆபத்தை குறைக்க நீல-பச்சை அல்லது கேனரி விநியோக உத்திகளைப் பயன்படுத்தவும்.

மைக்ரோசர்விஸ்கள் பாதுகாப்பு

சேவை-க்கு-சேவை அங்கீகாரம்

// auth-middleware.js
const jwt = require('jsonwebtoken');
const authenticateService = (req, res, next) => {
  const authHeader = req.headers.authorization;
  if (!authHeader) {
    return res.status(401).json({ message: 'No token provided' });
  }

  const token = authHeader.split(' ')[1];

  try {
    const decoded = jwt.verify(token, process.env.JWT_SECRET);
    if (decoded.iss !== 'auth-service') {
      return res.status(403).json({ message: 'Invalid token issuer' });
    }

    // Attach service info to request
    req.service = {
      id: decoded.sub,
      name: decoded.serviceName,
      permissions: decoded.permissions || []
    };

    next();
  } catch (error) {
    return res.status(401).json({ message: 'Invalid or expired token' });
  }
};

module.exports = authenticateService;

ரேட் லிமிடிங்

// rate-limiter.js
const rateLimit = require('express-rate-limit');
const RedisStore = require('rate-limit-redis');
const { createClient } = require('redis');
// Create Redis client

const redisClient = createClient({
  url: process.env.REDIS_URL
});

// Initialize rate limiter
const apiLimiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15 minutes
  max: 100, // Limit each IP to 100 requests per window
  standardHeaders: true, // Return rate limit info in the `RateLimit-*` headers
  store: new RedisStore({
    sendCommand: (...args) => redisClient.sendCommand(args)
  }),
  handler: (req, res) => {
    res.status(429).json({
      message: 'Too many requests, please try again later.'
    });
  }
});

module.exports = apiLimiter;

கண்காணிப்பு மற்றும் கண்காணிப்பு

OpenTelemetry உடன் விநியோகிக்கப்பட்ட ட்ரேசிங்

// tracing.js
const { NodeTracerProvider } = require('@opentelemetry/sdk-trace-node');
const { Resource } = require('@opentelemetry/resources');
const { SemanticResourceAttributes } = require('@opentelemetry/semantic-conventions');
const { BatchSpanProcessor } = require('@opentelemetry/sdk-trace-base');
const { JaegerExporter } = require('@opentelemetry/exporter-jaeger');
const { registerInstrumentations } = require('@opentelemetry/instrumentation');
const { HttpInstrumentation } = require('@opentelemetry/instrumentation-http');
const { ExpressInstrumentation } = require('@opentelemetry/instrumentation-express');


// Configure the tracer provider
const provider = new NodeTracerProvider({
  resource: new Resource({
    [SemanticResourceAttributes.SERVICE_NAME]: 'user-service',
    'service.version': '1.0.0',
  }),
});

// Configure Jaeger exporter
const exporter = new JaegerExporter({
  endpoint: process.env.JAEGER_ENDPOINT || 'http://localhost:14268/api/traces',
});

// Add the exporter to the provider
provider.addSpanProcessor(new BatchSpanProcessor(exporter));

// Initialize the OpenTelemetry APIs to use the NodeTracerProvider
provider.register();

// Register instrumentations
registerInstrumentations({
  instrumentations: [
    new HttpInstrumentation(),
    new ExpressInstrumentation(),
  ],
  tracerProvider: provider,
});

console.log('Tracing initialized');

கட்டமைக்கப்பட்ட பதிவு

// logger.js
const winston = require('winston');
const { combine, timestamp, json } = winston.format;

const logger = winston.createLogger({
  level: process.env.LOG_LEVEL || 'info',
  format: combine(
    timestamp(),
    json()
  ),
  defaultMeta: {
    service: 'user-service',
    environment: process.env.NODE_ENV || 'development',
  },
  transports: [
    new winston.transports.Console(),
    // Add other transports like file, ELK, etc.
  ],
});

// Add request ID to logs
logger.child = function(opts) {
  return new Proxy(logger, {
    get(target, property, receiver) {
      if (property === 'write') {
        return (...args) => {
          const originalMeta = args[args.length - 1] || {};
          args[args.length - 1] = { ...opts, ...originalMeta };
          return logger[property](...args);
        };
      }
      return Reflect.get(target, property, receiver);
    },
  });
};

module.exports = logger;

பயிற்சி

மைக்ரோசர்விஸ்களில், ஒரு சேவை பதிலளிக்காதபோது தொடர் தோல்விகளை தடுக்கும் வடிவத்தின் சரியான பெயரை தேர்வு செய்யவும்.

ரிட்ரை வித் பேக்அஃப்
✗ தவறு! "ரிட்ரை வித் பேக்அஃப்" என்பது தோல்வியுற்ற கோரிக்கைகளை தானாகவே மீண்டும் முயற்சிக்கும் வடிவமாகும்
டைம்அவுட் பேட்டர்ன்
✗ தவறு! "டைம்அவுட் பேட்டர்ன்" என்பது பதில்களுக்காக காத்திருக்க அதிகபட்ச நேரத்தை அமைக்கும் வடிவமாகும்
சர்க்யூட் பிரேக்கர்
✓ சரி! "சர்க்யூட் பிரேக்கர்" என்பது ஒரு சேவை பதிலளிக்காதபோது தொடர் தோல்விகளை தடுக்கும் சரியான வடிவமாகும்
பல்க்ஹெட் பேட்டர்ன்
✗ தவறு! "பல்க்ஹெட் பேட்டர்ன்" என்பது தோல்விகளை கூறுகளுக்குள் கொண்டிருக்கும் வடிவமாகும்